package wailsutil

import (
	"encoding/json"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strings"
	"syscall"
	"time"

	"github.com/jadefox10200/goprint"
)

var (
	pdfHtmlStr = `<!DOCTYPE html>
<html lang="zh-CN">
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="content-type" content="text/html;charset=utf-8">
		<meta http-equiv="X-UA-Compatible" content="IE=edge">
		<meta name="viewport" content="width=device-width,initial-scale=1.0">
	</head>
	<style>
		html, body{
			margin: 0;
			padding: 0;
			width: 100%;
			height: 100%;
		}
	</style>
<body>${htmlstr}
<body></html>`
)

// html打印信息
type HtmlToPdfInfo struct {
	PdfName     string    `json:"pdfName"`     //生成的pdf文件名
	CenterHtml  string    `json:"centerHtml"`  //正文
	HeadHtml    string    `json:"headHtml"`    //页头
	FootHtml    string    `json:"footHtml"`    //页脚
	PageSize    string    `json:"pageSize"`    //纸张大小(类型)
	PageWidth   string    `json:"pageWidth"`   //自定义纸张宽度
	PageHeight  string    `json:"pageHeight"`  //自定义纸张高度
	Orientation int       `json:"orientation"` //纸张方向
	Margin      []float64 `json:"margin"`      //页边距(上下左右)
}

/**
 * html转pdf
 * @param htmlInfo html信息
 * @return
 */
func HtmlToPdf(htmlInfo string) map[string]interface{} {
	if htmlInfo == "" {
		return map[string]interface{}{"success": false, "msg": "请求参数缺失", "data": 1001}
	}

	htmlToPdfInfo := HtmlToPdfInfo{}
	err := json.Unmarshal([]byte(htmlInfo), &htmlToPdfInfo)
	if err != nil {
		return map[string]interface{}{"success": false, "msg": "请求参数htmlInfo格式错误" + err.Error(), "data": 1002}
	}

	if htmlToPdfInfo.CenterHtml == "" {
		return map[string]interface{}{"success": false, "msg": "打印内容缺失", "data": 1003}
	}

	if htmlToPdfInfo.HeadHtml == "" {
		htmlToPdfInfo.HeadHtml = ""
	}

	if htmlToPdfInfo.FootHtml == "" {
		htmlToPdfInfo.FootHtml = ""
	}

	if htmlToPdfInfo.PdfName == "" {
		htmlToPdfInfo.PdfName = time.Now().Format("20060102150405")
	}

	if htmlToPdfInfo.PageSize == "" {
		htmlToPdfInfo.PageSize = "A4"
	}

	if htmlToPdfInfo.Orientation != 1 {
		htmlToPdfInfo.Orientation = 0
	}

	if (htmlToPdfInfo.Margin == nil) || (len(htmlToPdfInfo.Margin) != 4) {
		htmlToPdfInfo.Margin = []float64{1.0, 1.0, 1.0, 1.0}
	}

	dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
	if err != nil {
		dir = "./"
	} else {
		dir = strings.Replace(dir, "\\", "/", -1)
	}

	err = os.MkdirAll(dir+"/temp/pdf/tmp", 0755)
	if err != nil {
		return map[string]interface{}{"success": false, "msg": "创建临时目录失败:" + err.Error(), "data": 1004}
	}

	centerHtml := dir + "/temp/pdf/tmp/" + htmlToPdfInfo.PdfName + "/centerHtml.html"
	headHtml := dir + "/temp/pdf/tmp/" + htmlToPdfInfo.PdfName + "/headHtml.html"
	footHtml := dir + "/temp/pdf/tmp/" + htmlToPdfInfo.PdfName + "/footHtml.html"
	pdfPath := dir + "/temp/pdf/" + htmlToPdfInfo.PdfName + ".pdf"

	//删除临时文件
	defer func() {
		os.RemoveAll(centerHtml)
		os.RemoveAll(headHtml)
		os.RemoveAll(footHtml)
		os.RemoveAll(dir + "/temp/pdf/tmp/" + htmlToPdfInfo.PdfName)
	}()

	saveFile(centerHtml, strings.Replace(pdfHtmlStr, "${htmlstr}", htmlToPdfInfo.CenterHtml, -1))
	saveFile(headHtml, strings.Replace(pdfHtmlStr, "${htmlstr}", htmlToPdfInfo.HeadHtml, -1))
	saveFile(footHtml, strings.Replace(pdfHtmlStr, "${htmlstr}", htmlToPdfInfo.FootHtml, -1))

	//纸张方向
	orientation := "Landscape"
	if htmlToPdfInfo.Orientation != 1 {
		orientation = "Portrait"
	}

	programPath := dir + "/tools/wkhtmltopdf"

	// 获取程序的绝对路径
	programDir := filepath.Dir(programPath)

	// 构建wkhtmltopdf命令

	params := []string{}
	if strings.ToLower(htmlToPdfInfo.PageSize) == "custom" {
		params = append(params, "--page-width")
		params = append(params, htmlToPdfInfo.PageWidth)
		params = append(params, "--page-height")
		params = append(params, htmlToPdfInfo.PageHeight)
	} else {
		params = append(params, "--page-size")
		params = append(params, htmlToPdfInfo.PageSize)
	}

	params = append(params, "--orientation")
	params = append(params, orientation)
	params = append(params, "--margin-top")
	params = append(params, fmt.Sprintf("%.1fin", htmlToPdfInfo.Margin[0]))
	params = append(params, "--margin-bottom")
	params = append(params, fmt.Sprintf("%.1fin", htmlToPdfInfo.Margin[1]))
	params = append(params, "--margin-left")
	params = append(params, fmt.Sprintf("%.1fin", htmlToPdfInfo.Margin[2]))
	params = append(params, "--margin-right")
	params = append(params, fmt.Sprintf("%.1fin", htmlToPdfInfo.Margin[3]))

	if htmlToPdfInfo.HeadHtml != "" {
		params = append(params, "--header-html")
		params = append(params, headHtml)
	}

	if htmlToPdfInfo.FootHtml != "" {
		params = append(params, "--footer-html")
		params = append(params, footHtml)
	}

	params = append(params, "--encoding")
	params = append(params, "utf-8")
	params = append(params, centerHtml)
	params = append(params, pdfPath)

	cmd := exec.Command(programPath, params...)

	// 设置工作目录
	cmd.Dir = programDir

	// 设置隐藏窗口标志
	cmd.SysProcAttr = &syscall.SysProcAttr{
		HideWindow: true,
	}

	// 启动外部程序
	err = cmd.Start()
	if err != nil {
		return map[string]interface{}{"success": false, "msg": "请求打开引用程序" + programPath + "发生异常:" + err.Error(), "data": 1005}
	}

	//等待程序执行完成
	err = cmd.Wait()
	if err != nil {
		return map[string]interface{}{"success": false, "msg": "执行程序" + programPath + "发生异常:" + err.Error(), "data": 1006}
	}

	return map[string]interface{}{"success": true, "msg": "生成pdf成功", "data": pdfPath}
}

/**
 * html打印
 * @param htmlInfo html信息
 * @param printerDrive 打印机名称
 * @return
 */
func HtmlPrint(htmlInfo, printerDrive string) map[string]interface{} {
	me := HtmlToPdf(htmlInfo)
	if !me["success"].(bool) {
		return me
	}

	return PrintPdf(me["data"].(string), "", printerDrive)
}

/**
 * 打印机PDF文件
 * @param pdfPath 待打印文件路径
 * @param params 打印参数
 * @param printerDrive 打印机名称
 */
func PrintPdf(pdfPath, params, printerDrive string) map[string]interface{} {
	if pdfPath == "" {
		return map[string]interface{}{"success": false, "data": 1001, "msg": "待打印文件不存在"}
	}

	if printerDrive == "" {
		printerDrive, _ = goprint.GetDefaultPrinterName()
	}

	if runtime.GOOS == "windows" {
		dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
		if err != nil {
			return map[string]interface{}{"success": false, "data": 1003, "msg": "取程序路径异常:" + err.Error()}
		}

		// 获取程序的绝对路径
		dir = strings.Replace(dir, "\\", "/", -1)
		printServerExePath := dir + "/tools/SumatraPDF.exe"

		if strings.HasPrefix(pdfPath, "./") {
			pdfPath = dir + pdfPath[1:]
		}

		_, err = os.Stat(printServerExePath)
		if err != nil {
			return map[string]interface{}{"success": false, "data": 1004, "msg": "打印服务程序不存在:" + printServerExePath}
		}

		// cmdStr := fmt.Sprintf("\"%s\" -print-to \"%s\" \"%s\"", printServerExePath, printerDrive, pdfPath)
		// cmd := exec.Command(cmdStr)
		cmd := exec.Command(printServerExePath, "-print-to", printerDrive, pdfPath) //在windows下使用指定打印机静默打印

		// 设置工作目录
		cmd.Dir = filepath.Dir(printServerExePath)

		// 启动外部程序
		err = cmd.Start()
		if err != nil {
			return map[string]interface{}{"success": false, "data": 1005, "msg": "打开程序" + printServerExePath + "发生异常:" + err.Error()}
		}

		return map[string]interface{}{"success": true, "data": 1999, "msg": "打印信息已发送,请等待打印机打印完成"}
	} else { //linux
		//open the printer
		printerHandle, err := goprint.GoOpenPrinter(printerDrive)
		if err != nil {
			return map[string]interface{}{"success": false, "data": 1006, "msg": "取打印机信息失败" + err.Error()}
		}
		defer goprint.GoClosePrinter(printerHandle)

		err = goprint.GoPrint(printerHandle, pdfPath)
		if err != nil {
			return map[string]interface{}{"success": false, "data": 1007, "msg": "打印失败:" + err.Error()}
		}
	}

	return map[string]interface{}{"success": true, "data": 1999, "msg": "打印信息已发送,请等待打印机打印完成"}
}

// 保存文件内容
func saveFile(path string, text string) map[string]interface{} {
	if path == "" {
		return map[string]interface{}{"success": false, "data": 8001, "msg": "路径参数缺失"}
	}

	os.MkdirAll(filepath.Dir(path), 0755)

	file, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
	if err != nil {
		return map[string]interface{}{"success": false, "data": 8002, "msg": "打开文件异常:" + err.Error()}
	}

	defer file.Close()
	_, err = file.WriteString(text)
	if err != nil {
		return map[string]interface{}{"success": false, "data": 8003, "msg": "保存文件异常:" + err.Error()}
	}

	return map[string]interface{}{"success": true, "data": path, "msg": "保存文件成功"}
}
